﻿using MediatR;
using Microsoft.Extensions.Caching.Distributed;
using System.Text;
using System.Text.Json;

namespace CQRSLearn.Caching
{
    public class CachingBehavior<TRequest, TResponse>(ILogger<CachingBehavior<TRequest, TResponse>> logger, IDistributedCache cache) : IPipelineBehavior<TRequest, TResponse> where TRequest : ICacheable
    {
        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
        {
            TResponse response;
            if(request.BypassCache) return await next();
            async Task<TResponse> GetResponseAndAddToCache()
            {
                response=await next();
                if (response!=null)
                {
                    var sildingExpiration = request.SlidingExpirationInMinutes == 0 ? 30 : request.SlidingExpirationInMinutes;
                    var absoluteExpiration = request.AbsoluteExpirationInMinutes == 0 ? 60 : request.AbsoluteExpirationInMinutes;
                    var options = new DistributedCacheEntryOptions()
                              .SetSlidingExpiration(TimeSpan.FromMinutes(sildingExpiration))
                              .SetAbsoluteExpiration(TimeSpan.FromMinutes(absoluteExpiration));
                    var serializedData=Encoding.Default.GetBytes(JsonSerializer.Serialize(response));
                    await cache.SetAsync(request.CacheKey, serializedData,options,cancellationToken);
                }
                return response;
            }
            var cacheResponse=await cache.GetAsync(request.CacheKey,cancellationToken);
            if (cacheResponse != null)
            {
                response=JsonSerializer.Deserialize<TResponse>(Encoding.Default.GetString(cacheResponse))!;
                logger.LogInformation($"fetched from cache with key:{request.CacheKey}");
                cache.Refresh(request.CacheKey);
            }
            else
            {
                response = await GetResponseAndAddToCache();
                logger.LogInformation($"added to cache with key : {request.CacheKey}");
            }
            return response;
        }

    }
}
